﻿using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
using WMS.FC.Domain.DomainObject.System;
using WMS.FC.Domain.PersistenceObject;
using WMS.FC.Domain.Repository;
using WMS.FC.Infrastructure.Common;

namespace WMS.FC.Infrastructure.Repository
{
    public class RepositoryBase : IRepositoryBase
    {
        protected readonly WmsDbContext dbContext;

        public RepositoryBase(WmsDbContext dbContext)
        {
            this.dbContext = dbContext;
        }

        public async Task<int> Insert<TSource>(TSource entity, UserInfo userInfo) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            if (entity == null) return 0;

            if (entity.Id == 0)
                entity.Id = SnowflakeIdHelper.Instance.NextId();
            entity.CreatedBy = userInfo.UserName;
            entity.CreateDate = DateTime.Now;
            entity.ModifyIp = userInfo.UserIp;

            await entities.AddAsync(entity);
            return await dbContext.SaveChangesAsync();
        }

        public async Task<int> Insert<TSource>(List<TSource> entityList, UserInfo userInfo) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            if (entityList == null || !entityList.Any()) return 0;

            entityList.ForEach(entity =>
            {
                if (entity.Id == 0)
                    entity.Id = SnowflakeIdHelper.Instance.NextId();
                entity.CreatedBy = userInfo.UserName;
                entity.CreateDate = DateTime.Now;
                entity.ModifyIp = userInfo.UserIp;
            });

            await entities.AddRangeAsync(entityList);
            return await dbContext.SaveChangesAsync();
        }

        public async Task<int> Update<TSource>(TSource entity, UserInfo userInfo) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            if (entity == null) return 0;
            entity.ModifiedBy = userInfo.UserName;
            entity.ModifyDate = DateTime.Now;
            entity.ModifyIp = userInfo.UserIp;
            entities.Update(entity);
            return await dbContext.SaveChangesAsync();
        }

        public async Task<int> Update<TSource>(List<TSource> entityList, UserInfo userInfo) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            if (entityList == null || !entityList.Any()) return 0;
            entityList.ForEach(entity =>
            {
                entity.ModifiedBy = userInfo.UserName;
                entity.ModifyDate = DateTime.Now;
                entity.ModifyIp = userInfo.UserIp;
            });

            entities.UpdateRange(entityList);
            return await dbContext.SaveChangesAsync();
        }

        public async Task<int> Delete<TSource>(long id) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            if (id == 0) return 0;
            var entity = await entities.FindAsync(id);
            if (entity == null) return 0;
            entities.Remove(entity);
            return await dbContext.SaveChangesAsync();
        }

        public async Task<int> Delete<TSource>(TSource entity) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            if (entity == null) return 0;
            entities.Attach(entity);
            entities.Remove(entity);
            return await dbContext.SaveChangesAsync();
        }

        public async Task<int> Delete<TSource>(Expression<Func<TSource, bool>> expression) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            var entityList = await entities.Where(expression).ToListAsync();
            entities.RemoveRange(entityList);
            return await dbContext.SaveChangesAsync();
        }

        public async Task<List<TSource>> GetAll<TSource>() where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            return await entities.AsNoTrackingWithIdentityResolution().ToListAsync();
        }

        public async Task<int> GetCount<TSource>(Expression<Func<TSource, bool>> expression) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            return await entities.Where(expression).CountAsync();
        }

        public async Task<TSource?> FindById<TSource>(long id) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            return await entities.AsNoTrackingWithIdentityResolution().FirstOrDefaultAsync(entity => entity.Id == id);
        }

        public async Task<List<TSource>> FindByCondition<TSource>(Expression<Func<TSource, bool>> whereExpression) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            return await entities.AsNoTrackingWithIdentityResolution().Where(whereExpression).ToListAsync();
        }

        public async Task<List<TSource>> FindByConditionOrderby<TSource, TKey>(Expression<Func<TSource, bool>> whereExpression, Expression<Func<TSource, TKey>> keySelector) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            return await entities.AsNoTrackingWithIdentityResolution().Where(whereExpression).OrderBy(keySelector).ToListAsync();
        }

        public async Task<List<TSource>> FindByConditionOrderByDescending<TSource, TKey>(Expression<Func<TSource, bool>> whereExpression, Expression<Func<TSource, TKey>> keySelector) where TSource : POBase
        {
            var entities = dbContext.Set<TSource>();
            return await entities.AsNoTrackingWithIdentityResolution().Where(whereExpression).OrderByDescending(keySelector).ToListAsync();
        }
    }
}
